package com.boot.admin.modules.sys.ai.service;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.boot.admin.base.R;
import com.boot.admin.modules.sys.ai.model.entity.AiRole;
import com.boot.admin.modules.sys.ai.model.vo.AiMessageVO;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 本地SSE LLM服务 - 支持流式回调
 */
@Slf4j
@Service
public class LocalSseLlmService {

    private static final String SSE_URL = "http://localhost:8000/role-play/chat/stream";
    private static final int TIMEOUT_SECONDS = 60;

    private final OkHttpClient httpClient;

    public LocalSseLlmService() {
        this.httpClient = new OkHttpClient.Builder()
                .connectTimeout(30, TimeUnit.SECONDS)
                .writeTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS)
                .readTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS)
                .build();
    }

    /**
     * 生成AI回复 - 需要传入完整的角色信息
     */
    public R<String> generateResponse(AiRole role, List<AiMessageVO> history, String userInput, Boolean enableWebSearch) {
        try {
            if (role == null) {
                return R.NG("角色信息不能为空");
            }

            // 构建新格式的请求对象
            LocalLlmRequest request = buildLocalLlmRequest(role, null, userInput, enableWebSearch);

            // 通过SSE发送请求并获取响应
            String response = sendSseRequest(request);

            log.info("本地LLM响应成功，内容长度: {}", response.length());
            return R.OK(response);

        } catch (Exception e) {
            log.error("调用本地LLM失败", e);
            return R.NG("本地LLM调用失败: " + e.getMessage());
        }
    }

    /**
     * 兼容旧版本接口（将角色ID转换为角色对象）
     */
    public R<String> generateResponse(String systemPrompt, List<AiMessageVO> history, String userInput) {
        // 创建临时角色对象
        AiRole tempRole = new AiRole();
        tempRole.setId("default");
        tempRole.setRoleName("Default Assistant");
        tempRole.setSystemPrompt(systemPrompt);
        tempRole.setVoiceId("default_voice");

        return generateResponse(tempRole, history, userInput, false);
    }

    /**
     * 流式生成AI回复 - 支持回调处理每个chunk
     */
    public void generateResponseStreaming(AiRole role, List<AiMessageVO> history, String userInput,
                                          AiConversationService.StreamingCallback callback) {
        // 为了保持向后兼容，调用带enableWebSearch参数的方法，默认为false
        generateResponseStreaming(role, history, userInput, false, callback);
    }

    /**
     * 流式生成AI回复 - 支持回调处理每个chunk
     */
    public void generateResponseStreaming(AiRole role, List<AiMessageVO> history, String userInput,
                                          Boolean enableWebSearch, AiConversationService.StreamingCallback callback) {
        try {
            if (role == null) {
                callback.onError("角色信息不能为空");
                return;
            }

            // 构建新格式的请求对象
            LocalLlmRequest request = buildLocalLlmRequest(role, null, userInput, enableWebSearch);

            // 通过SSE发送流式请求
            sendSseStreamingRequest(request, callback);

        } catch (Exception e) {
            log.error("调用本地LLM流式服务失败", e);
            callback.onError("本地LLM调用失败: " + e.getMessage());
        }
    }

    /**
     * 构建本地LLM请求对象
     */
    private LocalLlmRequest buildLocalLlmRequest(AiRole role, List<AiMessageVO> history, String userInput, Boolean enableWebSearch) {
        LocalLlmRequest request = new LocalLlmRequest();

        // 构建角色信息
        RoleInfo roleInfo = new RoleInfo();
        roleInfo.setRoleId(role.getId());
        roleInfo.setRoleName(role.getRoleName());
        roleInfo.setVoiceId(role.getVoiceId());
        roleInfo.setSystemPrompt(role.getSystemPrompt());
        request.setRoleInfo(roleInfo);

        // 构建历史对话
        List<HistoryMessage> historyMessages = new ArrayList<>();
        if (history != null && !history.isEmpty()) {
            history.stream()
                    .sorted((m1, m2) -> Integer.compare(m1.getMessageIndex(), m2.getMessageIndex()))
                    .forEach(message -> {
                        HistoryMessage historyMsg = new HistoryMessage();
                        historyMsg.setRole(message.isFromUser() ? "user" : "assistant");
                        historyMsg.setContent(message.getContent());
                        historyMsg.setMessageIndex(message.getMessageIndex());
                        historyMessages.add(historyMsg);
                    });
        }
        request.setHistory(historyMessages);

        // 设置用户输入
        request.setUserInput(userInput);

        // 设置网络搜索开关
        request.setEnableWebSearch(enableWebSearch != null ? enableWebSearch : false);

        return request;
    }

    /**
     * 发送SSE请求 - 非流式模式
     */
    private String sendSseRequest(LocalLlmRequest request) throws IOException {
        String requestBody = JSONUtil.toJsonStr(request);
        log.info("发送本地LLM请求: {}", requestBody);

        Request httpRequest = new Request.Builder()
                .url(SSE_URL)
                .header("Accept", "text/event-stream")
                .header("Content-Type", "application/json")
                .header("Cache-Control", "no-cache")
                .post(RequestBody.create(requestBody, MediaType.parse("application/json")))
                .build();

        try (Response response = httpClient.newCall(httpRequest).execute()) {
            if (!response.isSuccessful()) {
                String errorBody = response.body() != null ? response.body().string() : "未知错误";
                log.error("SSE请求失败 - HTTP状态码: {}, 响应: {}", response.code(), errorBody);
                throw new IOException("SSE请求失败: HTTP " + response.code() + " - " + errorBody);
            }

            return parseSseStream(response);
        }
    }

    /**
     * 发送流式SSE请求 - 支持回调
     */
    private void sendSseStreamingRequest(LocalLlmRequest request, AiConversationService.StreamingCallback callback) {
        try {
            String requestBody = JSONUtil.toJsonStr(request);
            log.info("发送流式本地LLM请求: {}", requestBody);

            Request httpRequest = new Request.Builder()
                    .url(SSE_URL)
                    .header("Accept", "text/event-stream")
                    .header("Content-Type", "application/json")
                    .header("Cache-Control", "no-cache")
                    .post(RequestBody.create(requestBody, MediaType.parse("application/json")))
                    .build();

            Response response = httpClient.newCall(httpRequest).execute();

            if (!response.isSuccessful()) {
                String errorBody = response.body() != null ? response.body().string() : "未知错误";
                log.error("流式SSE请求失败 - HTTP状态码: {}, 响应: {}", response.code(), errorBody);
                callback.onError("SSE请求失败: HTTP " + response.code() + " - " + errorBody);
                return;
            }

            // 解析流式响应
            parseSseStreamWithCallback(response, callback);

        } catch (Exception e) {
            log.error("发送流式SSE请求失败", e);
            callback.onError("发送流式请求失败: " + e.getMessage());
        }
    }

    /**
     * 解析SSE流响应
     */
    private String parseSseStream(Response response) throws IOException {
        StringBuilder contentBuilder = new StringBuilder();

        try (BufferedReader reader = new BufferedReader(response.body().charStream())) {
            String line;
            while ((line = reader.readLine()) != null) {
                log.debug("SSE行数据: {}", line);

                // 处理SSE事件格式
                if (line.startsWith("data: ")) {
                    String data = line.substring(6).trim();

                    // 检查流结束标志
                    if ("[DONE]".equals(data) || "".equals(data)) {
                        log.debug("SSE流结束");
                        break;
                    }

                    try {
                        // 解析JSON数据
                        JSONObject jsonData = JSONUtil.parseObj(data);
                        String content = extractContentFromSseData(jsonData);

                        if (content != null && !content.isEmpty()) {
                            contentBuilder.append(content);
                            log.debug("提取内容: {}", content);
                        }

                    } catch (Exception e) {
                        log.warn("解析SSE数据失败: {}", data, e);
                        // 继续处理下一行，不中断整个流
                    }
                }
                // 处理事件类型行 (event: xxx)
                else if (line.startsWith("event: ")) {
                    String eventType = line.substring(7).trim();
                    log.debug("SSE事件类型: {}", eventType);

                    // 如果是结束事件，退出循环
                    if ("done".equals(eventType) || "end".equals(eventType)) {
                        log.debug("接收到结束事件");
                        break;
                    }
                }
                // 处理ID行 (id: xxx)
                else if (line.startsWith("id: ")) {
                    String eventId = line.substring(4).trim();
                    log.debug("SSE事件ID: {}", eventId);
                }
                // 空行表示事件结束
                else if (line.trim().isEmpty()) {
                    log.debug("SSE事件分隔符");
                }
            }
        }

        String result = contentBuilder.toString();
        log.info("SSE流解析完成，总内容长度: {}", result.length());
        return result;
    }

    /**
     * 解析流式SSE响应并调用回调
     */
    private void parseSseStreamWithCallback(Response response, AiConversationService.StreamingCallback callback) {
        StringBuilder lastSentContent = new StringBuilder(); // 新增：记录已发送的累积内容

        try (BufferedReader reader = new BufferedReader(response.body().charStream())) {
            String line;
            while ((line = reader.readLine()) != null) {
                log.debug("流式SSE行数据: {}", line);

                // 处理SSE事件格式
                if (line.startsWith("data: ")) {
                    String data = line.substring(6).trim();

                    // 检查流结束标志
                    if ("[DONE]".equals(data) || "".equals(data)) {
                        log.info("流式SSE流结束");
                        callback.onComplete();
                        break;
                    }

                    try {
                        // 解析JSON数据
                        JSONObject jsonData = JSONUtil.parseObj(data);
                        String content = extractContentFromSseData(jsonData);

                        if (content != null && !content.isEmpty()) {
                            // 关键修改：计算增量内容
                            String currentFullContent = lastSentContent.toString() + content;
                            String incrementalContent = content;

                            // 如果content是累积式的（包含之前的内容），则提取增量
                            if (content.startsWith(lastSentContent.toString())) {
                                incrementalContent = content.substring(lastSentContent.length());
                            }

                            // 只有当有新增内容时才回调
                            if (!incrementalContent.isEmpty()) {
                                lastSentContent.append(incrementalContent);
                                callback.onTextChunk(incrementalContent);
                                log.debug("回调处理增量chunk: {}", incrementalContent);
                            }
                        }

                    } catch (Exception e) {
                        log.warn("解析流式SSE数据失败: {}", data, e);
                        // 继续处理下一行，不中断整个流
                    }
                }
                // 处理事件类型行 (event: xxx)
                else if (line.startsWith("event: ")) {
                    String eventType = line.substring(7).trim();
                    log.debug("流式SSE事件类型: {}", eventType);

                    // 如果是结束事件，退出循环
                    if ("done".equals(eventType) || "end".equals(eventType)) {
                        log.debug("接收到流式结束事件");
                        callback.onComplete();
                        break;
                    }
                }
                // 处理ID行 (id: xxx)
                else if (line.startsWith("id: ")) {
                    String eventId = line.substring(4).trim();
                    log.info("流式SSE事件ID: {}", eventId);
                }
                // 空行表示事件结束
                else if (line.trim().isEmpty()) {
                    log.info("流式SSE事件分隔符");
                }
            }

            log.info("流式SSE解析完成");

        } catch (Exception e) {
            log.error("解析流式SSE失败", e);
            callback.onError("解析流式响应失败: " + e.getMessage());
        }
    }

    /**
     * 从SSE数据中提取内容
     */
    private String extractContentFromSseData(JSONObject jsonData) {
        try {
            // 尝试不同的JSON结构格式

            // 格式1: OpenAI兼容格式
            if (jsonData.containsKey("choices")) {
                Object choices = jsonData.get("choices");
                if (choices instanceof List) {
                    List<?> choicesList = (List<?>) choices;
                    if (!choicesList.isEmpty() && choicesList.get(0) instanceof JSONObject) {
                        JSONObject choice = (JSONObject) choicesList.get(0);
                        if (choice.containsKey("delta")) {
                            JSONObject delta = choice.getJSONObject("delta");
                            if (delta.containsKey("content")) {
                                return delta.getStr("content");
                            }
                        }
                    }
                }
            }

            // 格式2: 直接包含content字段
            if (jsonData.containsKey("content")) {
                return jsonData.getStr("content");
            }

            // 格式3: 包含text字段
            if (jsonData.containsKey("text")) {
                return jsonData.getStr("text");
            }

            // 格式4: 包含message字段
            if (jsonData.containsKey("message")) {
                Object message = jsonData.get("message");
                if (message instanceof JSONObject) {
                    JSONObject msgObj = (JSONObject) message;
                    if (msgObj.containsKey("content")) {
                        return msgObj.getStr("content");
                    }
                }
            }

            log.debug("未找到内容字段，JSON结构: {}", jsonData);
            return null;

        } catch (Exception e) {
            log.warn("提取SSE内容失败", e);
            return null;
        }
    }

    /**
     * 本地LLM请求格式
     */
    @Data
    public static class LocalLlmRequest {
        private RoleInfo roleInfo;
        private List<HistoryMessage> history;
        private String userInput;
        private Boolean enableWebSearch = false;
    }

    /**
     * 角色信息
     */
    @Data
    public static class RoleInfo {
        private String roleId;
        private String voiceId;
        private String roleName;
        private String systemPrompt;
    }

    /**
     * 历史消息
     */
    @Data
    public static class HistoryMessage {
        private String role;        // "user" 或 "assistant"
        private String content;
        private Integer messageIndex;
    }
}